﻿// -----------------------------------------------------------------------
// <copyright company="Christoph van der Fecht - VDsoft">
// Copyright (C) Christoph van der Fecht - VDsoft - All Rights Reserved
// Unauthorized copying of this file, via any medium is strictly prohibited,
// unless it is communicated and authorized by the copyright owner.
// </copyright>
// -----------------------------------------------------------------------

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using SeriesManager.Model;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Windows.Controls;
using TVDB.Model;

namespace SeriesManager.ViewModel
{
	/// <summary>
	/// ViewModel for the banner Management.
	/// </summary>
	public class BannerManagerViewModel : ViewModelBase
	{
		/// <summary>
		/// The SeriesPath.
		/// </summary>
		private string seriesPath = null;

		/// <summary>
		/// The Banners.
		/// </summary>
		private ObservableCollection<Model.Banner> seriesPoster = new ObservableCollection<Model.Banner>();

		/// <summary>
		/// The Fanarts.
		/// </summary>
		private ObservableCollection<Model.Banner> fanArts = new ObservableCollection<Model.Banner>();

		/// <summary>
		/// The CurrentBanner.
		/// </summary>
		private Model.Banner currentBanner = null;

		/// <summary>
		/// Currently selected mirror.
		/// </summary>
		private Mirror currentMirror = null;

		/// <summary>
		/// The SeasonGraphics.
		/// </summary>
		private Model.SeriesGraphics seasonGraphics = null;

		/// <summary>
		/// The SelectedTab.
		/// </summary>
		private TabItem selectedTab = null;

		/// <summary>
		/// The SelectedSeason.
		/// </summary>
		private BannerSeason selectedSeason = null;

		#region private commands

		/// <summary>
		/// Command to browse the folder for the series or season.
		/// </summary>
		private RelayCommand browseSeasonCommand = null;

		/// <summary>
		/// Command to store the currently selected image.
		/// </summary>
		private RelayCommand storeImageCommand = null;

		#endregion

		/// <summary>
		/// Initializes a new instance of the <see cref="BannerManagerViewModel"/> class.
		/// </summary>
		public BannerManagerViewModel()
		{
			if (this.IsInDesignMode)
			{
				List<Model.Banner> fanDummy = new List<Model.Banner>()
				{
					new Model.Banner
					{
						Id = 1018362,
						BannerPath = "http://www.thetvdb.com/banners/fanart/original/259030-10.jpg",
						Typ = BannerTyp.fanart,
						ThumbnailPath = "http://www.thetvdb.com/banners/_cache/fanart/original/259030-10.jpg"
					},

					new Model.Banner
					{
						Id = 1011282,
						BannerPath = "http://www.thetvdb.com/banners/fanart/original/259030-5.jpg",
						Typ = BannerTyp.fanart,
						ThumbnailPath = "http://www.thetvdb.com/banners/_cache/fanart/original/259030-5.jpg"
					},

					new Model.Banner
					{
						Id = 970780,
						BannerPath = "http://www.thetvdb.com/banners/fanart/original/259030-2.jpg",
						Typ = BannerTyp.fanart,
						ThumbnailPath = "http://www.thetvdb.com/banners/_cache/fanart/original/259030-2.jpg"
					},

					new Model.Banner
					{
						Id = 1018359,
						BannerPath = "http://www.thetvdb.com/banners/fanart/original/259030-8.jpg",
						Typ = BannerTyp.fanart,
						ThumbnailPath = "http://www.thetvdb.com/banners/_cache/fanart/original/259030-8.jpg"
					}
				};

				List<Model.Banner> seasonDummy = new List<Model.Banner>()
				{
					new Model.Banner
					{ 
						BannerPath = "http://www.thetvdb.com/banners/seasons/259030-1.jpg",
						Id = 1011286,
						Typ = BannerTyp.season
					},

					new Model.Banner
					{ 
						BannerPath = "http://www.thetvdb.com/banners/seasons/259030-1-2.jpg",
						Id = 1020016,
						Typ = BannerTyp.season
					}
				};

				Model.BannerSeason dummySeason = new Model.BannerSeason
				{
					Season = 1,
					Banners = new ObservableCollection<Model.Banner>(seasonDummy)
				};

				this.SeasonGraphics = new Model.SeriesGraphics();
				this.SeasonGraphics.AddSeason(dummySeason);

				List<Model.Banner> seriesDummy = new List<Model.Banner>
				{
					new Model.Banner
					{ 
						BannerPath = "http://www.thetvdb.com/banners/graphical/259030-g.jpg",
						Id = 908660,
						Typ = BannerTyp.series
					},

					new Model.Banner
					{ 
						BannerPath = "http://www.thetvdb.com/banners/graphical/259030-g5.jpg",
						Id = 1014220,
						Typ = BannerTyp.series
					},

					new Model.Banner
					{ 
						BannerPath = "http://www.thetvdb.com/banners/graphical/259030-g2.jpg",
						Id = 910327,
						Typ = BannerTyp.series
					}
				};

				this.FanArts = new ObservableCollection<Model.Banner>(fanDummy);
				this.SeriesPoster = new ObservableCollection<Model.Banner>(seriesDummy);
				this.SeriesPath = @"C:\Some\Folder\Path";
			}
			else
			{
				Messenger.Default.Register<Mirror>(this, ViewModelLocator.SearchSeriesToken, this.ReceiveMirror);
				Messenger.Default.Register<List<Model.Banner>>(this, ViewModelLocator.SeriesBannerToken, this.ReceiveBanners);
			}
		}

		/// <summary>
		/// Gets or sets the Banners.
		/// </summary>
		public ObservableCollection<Model.Banner> SeriesPoster
		{
			get
			{
				return this.seriesPoster;
			}

			set
			{
				if (value == this.seriesPoster)
				{
					return;
				}

				this.seriesPoster = value;
				this.RaisePropertyChanged("SeriesPoster");
			}
		}

		/// <summary>
		/// Gets or sets the Fanarts.
		/// </summary>
		public ObservableCollection<Model.Banner> FanArts
		{
			get
			{
				return this.fanArts;
			}

			set
			{
				if (value == this.fanArts)
				{
					return;
				}

				this.fanArts = value;
				this.RaisePropertyChanged("FanArts");
			}
		}

		/// <summary>
		/// Gets or sets the CurrentBanner.
		/// </summary>
		public Model.Banner CurrentBanner
		{
			get
			{
				return this.currentBanner;
			}

			set
			{
				if (value == this.currentBanner)
				{
					return;
				}

				this.currentBanner = value;
				this.RaisePropertyChanged("CurrentBanner");
			}
		}

		/// <summary>
		/// Gets the current Mirror.
		/// </summary>
		public Mirror CurrentMirror
		{
			get
			{
				return this.currentMirror;
			}
		}

		/// <summary>
		/// Gets or sets the SeasonGraphic.
		/// </summary>
		public Model.SeriesGraphics SeasonGraphics
		{
			get
			{
				return this.seasonGraphics;
			}

			set
			{
				if (value == this.seasonGraphics)
				{
					return;
				}

				this.seasonGraphics = value;
				this.RaisePropertyChanged("SeasonGraphics");
			}
		}

		/// <summary>
		/// Gets or sets the SeriesPath.
		/// </summary>
		public string SeriesPath
		{
			get
			{
				return this.seriesPath;
			}

			set
			{
				if (value == this.seriesPath)
				{
					return;
				}

				this.seriesPath = value;
				this.RaisePropertyChanged("SeriesPath");
			}
		}

		/// <summary>
		/// Gets or sets the SelectedTab.
		/// </summary>
		public TabItem SelectedTab
		{
			get
			{
				return this.selectedTab;
			}

			set
			{
				if (value == this.selectedTab)
				{
					return;
				}

				this.selectedTab = value;
				this.RaisePropertyChanged();
			}
		}

		/// <summary>
		/// Gets or sets the SelectedSeason.
		/// </summary>
		public BannerSeason SelectedSeason
		{
			get
			{
				return this.selectedSeason;
			}

			set
			{
				if (value == this.selectedSeason)
				{
					return;
				}

				this.selectedSeason = value;
				this.RaisePropertyChanged();
			}
		}

		#region public commands

		/// <summary>
		/// Gets the command to browse for a series or season.
		/// </summary>
		public RelayCommand BrowseSeasonCommand
		{
			get
			{
				if (this.browseSeasonCommand == null)
				{
					this.browseSeasonCommand = new RelayCommand(this.BrowseSeries);
				}

				return this.browseSeasonCommand;
			}
		}

		/// <summary>
		/// Gets the command to store the currently selected image.
		/// </summary>
		public RelayCommand StoreImageCommand
		{
 			get
			{
				if (this.storeImageCommand == null)
				{
					this.storeImageCommand = new RelayCommand(this.StoreImage);
				}

				return this.storeImageCommand;
			}
		}

		#endregion

		/// <summary>
		/// Receives the currently selected mirror.
		/// </summary>
		/// <param name="received">Mirror that was selected by the user.</param>
		private void ReceiveMirror(Mirror received)
		{
			if (received == null)
			{
				return;
			}

			this.currentMirror = received;
		}

		/// <summary>
		/// Receives all banners for the selected series.
		/// </summary>
		/// <param name="banners">Collection of all banners for the currently selected series.</param>
		private void ReceiveBanners(List<Model.Banner> banners)
		{
			if (banners == null || banners.Count == 0)
			{
				return;
			}

			if (this.currentMirror == null)
			{
				return;
			}

			foreach (Model.Banner current in banners)
			{
				current.BannerPath = string.Format("{0}/banners/{1}", this.currentMirror.Address, current.BannerPath);

				switch (current.Typ)
				{
					case BannerTyp.fanart:
						{
							if (!string.IsNullOrEmpty(current.ThumbnailPath))
							{
								current.ThumbnailPath = string.Format("{0}/banners/{1}", this.currentMirror.Address, current.ThumbnailPath);
							}
							break;
						}
					case BannerTyp.poster:
					case BannerTyp.season:
					case BannerTyp.series:
					case BannerTyp.unknown:
					default:
						break;
				}
			}



			this.SeriesPoster = new ObservableCollection<Model.Banner>(banners.Where(x => x.Typ == BannerTyp.series).ToList());
			this.SeasonGraphics = this.GenerateSeasonGraphics(banners.Where(x => x.Typ == BannerTyp.season));
			this.FanArts = new ObservableCollection<Model.Banner>(banners.Where(x => x.Typ == BannerTyp.fanart).ToList());

			this.SeriesPoster = new ObservableCollection<Model.Banner>(banners);
		}

		/// <summary>
		/// Builds the seasons and graphics for the season.
		/// </summary>
		/// <param name="banners">Collection of graphics for the seasons.</param>
		/// <returns><see cref="Model.SeriesGraphics"/> object with all seasons and banners.</returns>
		private Model.SeriesGraphics GenerateSeasonGraphics(IEnumerable<Model.Banner> banners)
		{
			if (banners == null || banners.Count() == 0)
			{
				return null;
			}

			Model.SeriesGraphics result = new Model.SeriesGraphics();

			foreach (Model.Banner current in banners)
			{
				Model.BannerSeason currentSeason = result.Seasons.SingleOrDefault(x => x.Season == current.SeasonsNumber);
				if (currentSeason == null)
				{
					Model.BannerSeason toAdd = new Model.BannerSeason
					{
						Season = current.SeasonsNumber
					};

					toAdd.AddBanner(current);
					result.AddSeason(toAdd);
				}
				else
				{
					currentSeason.AddBanner(current);
				}
			}

			result.Seasons = new ObservableCollection<Model.BannerSeason>(result.Seasons.OrderBy(x => x.Season).ToList());

			return result;
		}

		/// <summary>
		/// Opens a folder dialog to browse for the series.
		/// </summary>
		private void BrowseSeries()
		{
			System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();
			dialog.SelectedPath = this.SeriesPath;

			if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
			{
				this.SeriesPath = dialog.SelectedPath;
			}
		}

		/// <summary>
		/// Stores the current selected image.
		/// </summary>
		private void StoreImage()
		{
			if (this.currentBanner == null)
			{
				return;
			}

			if (string.IsNullOrEmpty(this.seriesPath))
			{
				return;
			}

			string filename = this.DetermFileName();

			if (string.IsNullOrEmpty(filename))
			{
				return;
			}

			WebClient client = new WebClient();
			client.DownloadFileCompleted += OnDownloadFileCompleted;
			////string filePath = System.IO.Path.Combine(this.seriesPath, "folder.jpg");
			string filePath = System.IO.Path.Combine(this.seriesPath, filename);

			if (System.IO.File.Exists(filePath))
			{
				System.IO.File.Delete(filePath);
			}

			client.DownloadFileAsync(new Uri(this.CurrentBanner.BannerPath), filePath);
		}

		/// <summary>
		/// Determs the filename to use.
		/// </summary>
		/// <returns>Filename to use.</returns>
		private string DetermFileName()
		{
			NamingConventions convention = (NamingConventions)Enum.Parse(typeof(NamingConventions), Properties.Settings.Default.NamingConventions);

			string filename = null;

			switch (convention)
			{
				case NamingConventions.WindowsMediaCenter:
					{
						filename = "folder.jpg";
						break;
					}
				case NamingConventions.PlexMediaServer:
					{
						if (this.selectedTab == null)
						{
							break;
						}

						if (this.selectedTab.Header.Equals("Fanarts"))
						{
							filename = "fanart.jpg";
						}
						else if (this.selectedTab.Header.Equals("Season Poster"))
						{
							filename = string.Format("season-{0}.jpg", this.selectedSeason.Season.ToString("D2"));
						}
						else if (this.selectedTab.Header.Equals("Series Poster"))
						{
							filename = "show.jpg";
						}
						else
						{
							filename = null;
						}
						break;
					}
				default:
					{
						break;
					}
			}

			return filename;
		}

		private void OnDownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
		{
			((WebClient)sender).DownloadFileCompleted -= this.OnDownloadFileCompleted;
			
			if (e.Error == null)
			{
				this.CurrentBanner = null;
				this.SeriesPath = string.Empty;
			}
		}
	}
}